package com.mercycrazy.recruit.service.impl;

import com.mercycrazy.recruit.dao.AdminDao;
import com.mercycrazy.recruit.entity.Admin;
import com.mercycrazy.recruit.enums.StatusCode;
import com.mercycrazy.recruit.exception.BusinessException;
import com.mercycrazy.recruit.filter.AccessContext;
import com.mercycrazy.recruit.service.IAdminService;
import com.mercycrazy.recruit.user.CreateAdmin;
import com.mercycrazy.recruit.user.ResetAdminPwd;
import com.mercycrazy.recruit.user.SimpleAdminInfo;
import com.mercycrazy.recruit.util.MD5Util;
import com.mercycrazy.recruit.util.RandomUtil;
import com.mercycrazy.recruit.vo.PagedGridResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * Admin 相关服务接口实现
 *
 * @author <a href="mailto:1443424326@qq.com">mercycrazy</a>
 * @since 2023-01-18
 */
@Slf4j
@Service
public class AdminServiceImpl implements IAdminService {

    private final AdminDao adminDao;

    public AdminServiceImpl(AdminDao adminDao) {
        this.adminDao = adminDao;
    }

    @Override
    public void createAdmin(CreateAdmin createAdmin) {

        // 1. 判断该用户是否已经创建过
        adminDao.findFirstByUsername(
                        createAdmin.getUsername())
                .ifPresent(admin -> {
                    throw new BusinessException(StatusCode.ADMIN_USERNAME_EXIST_ERROR);
                });

        // 2. 创建一个新的 Admin
        Admin newAdmin = new Admin();

        newAdmin.setUsername(createAdmin.getUsername());
        newAdmin.setRemark(createAdmin.getRemark());
        newAdmin.setFace("");

        // 3. 生成随机盐, 和明文密码加密, 生成密文
        String salt = RandomUtil.getStringNumRandom(4);
        String encryptPwd = MD5Util.encrypt(createAdmin.getPassword(), salt);
        newAdmin.setSalt(salt);
        newAdmin.setPassword(encryptPwd);

        adminDao.save(newAdmin);
    }

    @Override
    public PagedGridResult adminListPaged(String username,
                                          Integer page, Integer limit) {

        if (page < 1) page = 1;
        if (limit < 1) limit = 10;

        Pageable pageable = PageRequest.of(page - 1, limit);

        Page<Admin> adminPage = adminDao.findAll(
                (Specification<Admin>) (root, query, criteriaBuilder) -> {
                    List<Predicate> predicates = new ArrayList<>();
                    if (StringUtils.isNotBlank(username)) {
                        predicates.add(
                                criteriaBuilder.like(root.get("username"), "%" + username + "%")
                        );
                    }
                    return query.where(
                            predicates.toArray(new Predicate[0])
                    ).getRestriction();
                }, pageable);

        return PagedGridResult.of(adminPage, Admin::toSimple);
    }

    @Override
    public void deleteAdmin(String username) {

        if (Objects.equals(username, "admin")) {
            throw new BusinessException(StatusCode.ADMIN_DELETE_ERROR);
        }

        // 获取请求者的 username
        String executors = AccessContext.getLoginAdminInfo().getUsername();

        if (!Objects.equals(executors, "admin") && !Objects.equals(executors, username)) {
            throw new BusinessException(StatusCode.ADMIN_DELETE_ERROR);
        }

        Integer rows = adminDao.deleteAdminByUsernameEquals(username);

        if (rows == 0) {
            throw new BusinessException(StatusCode.ADMIN_DELETE_ERROR);
        }
    }

    @Override
    public void resetAdminPwd(ResetAdminPwd resetAdminPwd) {

        if (!resetAdminPwd.validatePwd()) {
            throw new BusinessException(StatusCode.ADMIN_PASSWORD_ERROR);
        }

        // username = admin 可以修改所有人的密码
        // 其他 admin 用户只能修改自己的密码
        SimpleAdminInfo adminInfo = AccessContext.getLoginAdminInfo();
        if (!Objects.equals(adminInfo.getUsername(), "admin")
                && !Objects.equals(resetAdminPwd.getAdminId(), adminInfo.getId())) {
            throw new BusinessException(StatusCode.ADMIN_FORBIDDEN_RESET_PASSWORD);
        }

        Admin admin = adminDao.findById(resetAdminPwd.getAdminId()).orElse(null);
        if (null == admin) {
            throw new BusinessException(StatusCode.ADMIN_NOT_EXIST);
        }

        String salt = RandomUtil.getStringNumRandom(4);
        admin.setSalt(salt);
        admin.setPassword(
                MD5Util.encrypt(resetAdminPwd.getPassword(), salt)
        );

        adminDao.save(admin);
    }
}
